%%%-------------------------------------------------------------------
%%% @author shisj
%%% @copyright (C) 2016, <COMPANY>
%%% @doc
%%% 资源差异打包工具
%%% @end
%%% Created : 01. 七月 2016 11:07
%%%-------------------------------------------------------------------

-module(lj_version).

-behaviour(wx_object).

%% Client API
-export([start/1, start_whole_cmd/1, start_diff_cmd/1, start_code_cmd/1, start_zip_cmd/1]).

%% wx_object callbacks
-export([init/1, terminate/2,  code_change/3,
	 handle_info/2, handle_call/3, handle_cast/2, handle_event/2]).

-include_lib("wx/include/wx.hrl").
-include_lib("xmerl/include/xmerl.hrl").
-include_lib("kernel/include/file.hrl").

-record(state, 
	{
	  parent,
	  config,
    appVer,
    pfCode,
    resVer,
    pack,
    doMains,
    clientUrl
	}).

-record(input,
{
  app_version,
  pfcode,
  res_version,
  pack,
  domains,
  game_root,
  state
}).

start(Config) ->
    wx_object:start_link(?MODULE, Config, []).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init(Config) ->
    wx:batch(fun() -> do_init(Config) end).

do_init(Config) ->
    Parent = proplists:get_value(parent, Config),
    Panel = wxPanel:new(Parent, []),

    %% Setup sizers
    MainSizer = wxBoxSizer:new(?wxVERTICAL),
    Sizer1 = wxBoxSizer:new(?wxHORIZONTAL),

    AppVersionSizer = wxStaticBoxSizer:new(?wxVERTICAL, Panel,[{label, "游戏版本号"}]),
    PfCodeSizer = wxStaticBoxSizer:new(?wxVERTICAL,Panel,[{label,"渠道号标识"}]),
    ResSizer = wxStaticBoxSizer:new(?wxVERTICAL,Panel,[{label,"资源版本号"}]),
    PackSizer = wxStaticBoxSizer:new(?wxVERTICAL,Panel,[{label,"资源补丁包号"}]),
    DomainsSizer = wxStaticBoxSizer:new(?wxVERTICAL,Panel,[{label,"域名列表"}]),
    ClientSizer = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "游戏项目地址"}]),
    ButtonsSizer = wxStaticBoxSizer:new(?wxHORIZONTAL, Panel, [{label, "控制框"}]),


    Labels = [{"打整游戏包",2},{"打差异资源包",1},{"单独打包代码",3},{"手动zip打包",4}],
    Buttons = [wxButton:new(Panel, Id, [{label, L}])|| {L,Id} <- Labels],

    AppVersionTextCtrl  = wxTextCtrl:new(Panel, 1, [{style, ?wxDEFAULT},{value,"0.0.1"}]),
    PfCodeTextCtrl = wxTextCtrl:new(Panel,2,[{style,?wxDEFAULT},{value,"hwy"}]),
    ResTextCtrl = wxTextCtrl:new(Panel,3,[{style,?wxDEFAULT},{value,"0"}]),
    PackTextCtrl = wxTextCtrl:new(Panel,3,[{style,?wxDEFAULT},{value,"0"}]),
    DomainsTextCtrl = wxTextCtrl:new(Panel,3,[{style,?wxDEFAULT},{value,"src.cdn.haowanyou.com,203.195.143.191,119.29.47.91"}]),

    ClientPicker = wxDirPickerCtrl:new(Panel,3,[{path,""}]),

    wxDirPickerCtrl:connect(ClientPicker,command_dirpicker_changed,[]),

    %% Add to sizers
    SizerOptions  = [{flag, ?wxEXPAND}],

    wxSizer:add(AppVersionSizer, AppVersionTextCtrl,  []),
    wxSizer:add(PfCodeSizer,PfCodeTextCtrl,[]),
    wxSizer:add(ResSizer,ResTextCtrl,[]),
    wxSizer:add(PackSizer,PackTextCtrl,[]),
    wxSizer:add(DomainsSizer,DomainsTextCtrl,SizerOptions),
    wxSizer:add(ClientSizer,ClientPicker,SizerOptions),


    wxSizer:add(Sizer1, AppVersionSizer, []),
    wxSizer:addSpacer(Sizer1, 10),
    wxSizer:add(Sizer1, PfCodeSizer,[]),
    wxSizer:addSpacer(Sizer1, 10),
    wxSizer:add(Sizer1, ResSizer,[]),
    wxSizer:addSpacer(Sizer1, 10),
    wxSizer:add(Sizer1, PackSizer,[]),

    wxSizer:add(MainSizer, Sizer1,  SizerOptions),
    wxSizer:add(MainSizer,DomainsSizer,SizerOptions),
    wxSizer:addSpacer(MainSizer, 10),
    wxSizer:add(MainSizer, ClientSizer,SizerOptions),

    [wxSizer:add(ButtonsSizer, Button) || Button <- Buttons],
    wxPanel:connect(Panel, command_button_clicked),
    wxSizer:add(MainSizer, ButtonsSizer),

    wxPanel:setSizer(Panel, MainSizer),

    State = #state{
      parent = Panel,
      config = Config,
      appVer = AppVersionTextCtrl,
      pfCode = PfCodeTextCtrl,
      resVer = ResTextCtrl,
      pack = PackTextCtrl,
      doMains = DomainsTextCtrl,
      clientUrl = ClientPicker
    },

    {Panel, State}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Async Events are handled in handle_event as in handle_info
handle_event(#wx{event = #wxFontPicker{font = Font}}, State = #state{}) ->
    tools:format(State#state.config, "Font changed to ~p.\n", [Font]),
    {noreply, State};
handle_event(#wx{event = #wxColourPicker{colour = Colour}}, State = #state{}) ->
    tools:format(State#state.config, "Colour changed to ~p.\n", [Colour]),
    {noreply, State};
handle_event(#wx{event = #wxFileDirPicker{type = command_filepicker_changed,
					  path = Path}},
	     State = #state{}) ->
    tools:format(State#state.config, "Filepicker changed to ~p.\n", [Path]),
    {noreply, State};
handle_event(#wx{id = Id, event = #wxFileDirPicker{type = command_dirpicker_changed,
  path = Path}},
    State = #state{}) ->
    case Id of
      1-> no;
      2-> no;
      3->
        GameConfPath = format_path(Path++"/svn_1_package/Assets/StreamingAssets/gameConf.json"),
        case file:read_file(GameConfPath) of
          {ok,Binary}->
            GameConf = binary_to_list(Binary),
            setDate_To_wxInput(GameConf,State);
          {error,Reason}-> tools:messageDialog(State#state.config,"该项目下面不存在gameConf.json文件")
        end
    end,
  {noreply, State};
handle_event(#wx{id = Id,
  event = #wxCommand{type = command_button_clicked}},
    State = #state{parent=Parent}) ->
    case Id of
      1 -> input_msg(State,fun lj_version:start_diff_cmd/1);
      2 -> input_msg(State,fun lj_version:start_whole_cmd/1);
      3 -> input_msg(State,fun lj_version:start_code_cmd/1);
      4 -> input_msg(State,fun lj_version:start_zip_cmd/1);
      _ -> ignore
    end,
  {noreply, State};
handle_event(#wx{event = #wxDate{date = Date}},
	     State = #state{}) ->
    tools:format(State#state.config, "Datepicker changed to ~p.\n", [Date]),
    {noreply, State};
handle_event(Ev = #wx{}, State = #state{}) ->
    tools:format(State#state.config, "Got Event ~p\n", [Ev]),
    {noreply, State}.

%% Callbacks handled as normal gen_server callbacks
handle_info(Msg, State) ->
    tools:format(State#state.config, "Got Info ~p\n", [Msg]),
    {noreply, State}.

handle_call(shutdown, _From, State=#state{parent=Panel}) ->
    wxPanel:destroy(Panel),
    {stop, normal, ok, State};

handle_call(Msg, _From, State) ->
    tools:format(State#state.config, "Got Call ~p\n", [Msg]),
    {reply,{error, nyi}, State}.

handle_cast(Msg, State) ->
    io:format("Got cast ~p~n",[Msg]),
    {noreply,State}.


code_change(_, _, State) ->
    {stop, ignore, State}.

terminate(_Reason, _State) ->
    ok.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Local functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%indie([{Fun, Args}]) ->
%%  Fun(Args);
%%indie([{Fun, Args}|T]) ->
%%  case Fun(Args) of
%%    {fail, Reason} -> {fail, Reason};
%%    _ -> indie(T)
%%  end.

%%输入信息
input_msg(State,F) when is_function(F,1)->

  App_version = wxTextCtrl:getValue(State#state.appVer),
  Pf_code = wxTextCtrl:getValue(State#state.pfCode),
  Res_version = wxTextCtrl:getValue(State#state.resVer),
  Pack_version = wxTextCtrl:getValue(State#state.pack),
  Domains = wxTextCtrl:getValue(State#state.doMains),
  Game_Root = wxDirPickerCtrl:getPath(State#state.clientUrl),

  Inputs = [{App_version,"游戏版本号"},{Pf_code,"渠道号标识"},{Domains,"域名列表"},{Game_Root,"游戏项目地址"}],
  InputR = #input{app_version = App_version,pfcode = Pf_code,domains = Domains,game_root = Game_Root,state = State, res_version = Res_version, pack = Pack_version},

  Result = input_f(Inputs),
  case Result of
    {pass,_}-> F(InputR);
    {fail,Reason}->Msg = Reason++"不能为空", tools:messageDialog(State#state.config,Msg)
  end,
  ok.

setDate_To_wxInput(GameConf,State)->
  {ok,{obj,Info},_} = rfc4627:decode(GameConf),
  [P|T1] = Info,
  [A|T2] = T1,
  [D|T3] = T2,
  [R|T4] = T3,
  [Pa|_] = T4,
  {"pfcode",Pf_code} = P,
  {"app_version",App_version} = A,
  {"domains",Domains} = D,
  {"res_version",Res_version} = R,
  {"pack",Pack_version} = Pa,

  wxTextCtrl:setValue(State#state.appVer,binary_to_list(App_version)),
  wxTextCtrl:setValue(State#state.pfCode,binary_to_list(Pf_code)),
  wxTextCtrl:setValue(State#state.doMains,binary_to_list(Domains)),
  wxTextCtrl:setValue(State#state.resVer,binary_to_list(Res_version)),
  wxTextCtrl:setValue(State#state.pack,binary_to_list(Pack_version)),
  ok.

%%开始打整包
start_whole_cmd(InputR)->
  tools:format(InputR#input.state#state.config,"开始打整包~n",[]),
  %%创建gameConf.json文件
  GameConfObj = {obj,
    [{"pfcode",list_to_binary(InputR#input.pfcode)},
      {"app_version",list_to_binary(InputR#input.app_version)},
      {"domains",list_to_binary(InputR#input.domains)},
      {"res_version",list_to_binary(InputR#input.res_version)},
      {"pack",list_to_binary(InputR#input.pack)},
      {"isUpdateVer",list_to_binary("1")},
      {"updateCode",list_to_binary("1")},
      {"updateUi",list_to_binary("1")},
      {"updateEffect",list_to_binary("1")},
      {"updateAudio",list_to_binary("1")},
      {"updateCharactor",list_to_binary("1")},
      {"updateTerrainData",list_to_binary("1")}
    ]},
  Json = rfc4627:encode(GameConfObj),
  GameConfPath = format_path(InputR#input.game_root++"/svn_1_package/Assets/StreamingAssets/gameConf.json"),

  %%alter_string(InputR),

  file:write_file(GameConfPath, list_to_binary(Json)),
  tools:format(InputR#input.state#state.config,"创建gameConf.json文件 ~n",[]),
  tools:format(InputR#input.state#state.config,"正在打包中，不要关闭软件，请稍等…… ~n",[]),
  wxPanel:disable(InputR#input.state#state.parent),
  c:cd(InputR#input.game_root),
  os:cmd("start 1_build_whole_project.bat"),
  start_zip_pack(InputR),
  wxPanel:enable(InputR#input.state#state.parent),
  ok.

%%修改tools\Android\res\values\versions.xml
alter_string(InputR)->
  case erlang:system_info(os_type) of
    {unix,_}->
      nothing;
    {win32,_}->
      manifast(InputR)
  end,
  ok.

-define(xml_prolog, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>").
manifast(InputR)->
  ManiFast_Path = format_path(InputR#input.game_root++"/tools/Android/AndroidManifest.xml"),
  {XmlElt, _} = xmerl_scan:file(ManiFast_Path),
  [#xmlAttribute{value = VersionCode}] = xmerl_xpath:string("/manifest/@android:versionCode", XmlElt),
  [#xmlAttribute{value = VersionName}] = xmerl_xpath:string("/manifest/@android:versionName", XmlElt),

  io:format("VersionCode ~ts ~n",[VersionCode]),
  io:format("VersionName ~ts ~n",[VersionName]),
  io:format("~w ~n",[XmlElt]),
  NewVersionName = InputR#input.app_version,
  NewVersionCode = integer_to_list(list_to_integer(VersionCode)+1),
  io:format("NewVersionCode ~ts ~n",[NewVersionCode]),
  io:format("NewVersionName ~ts ~n",[NewVersionName]),


  XmlString = xmerl:export_simple([XmlElt], xmerl_xml,[{prolog, ?xml_prolog}]),
  unicode:characters_to_binary(XmlString),
  file:write_file(ManiFast_Path, list_to_binary(XmlString)),

  ok.

%%read_string(InputR)->
%%  StringPath = format_path(InputR#input.game_root++"/tools/strings.xml"),
%%  case file:read_file_info(StringPath) of
%%    {ok,_}->
%%      {XmlElt, _} = xmerl_scan:file(StringPath),
%%      Items = xmerl_xpath:string("/resources/string", XmlElt),
%%      ItemList = lists:map(fun(Item)->
%%        [#xmlAttribute{value = Name}] = xmerl_xpath:string("/string/@name", Item),
%%        [#xmlText{value = Value}] = xmerl_xpath:string("/string/text()",Item),
%%        if
%%          Name == "app_versionName" ->
%%            tools:format(InputR#input.state#state.config,"新版本号: ~ts ~n",[InputR#input.app_version]),
%%            {Name,InputR#input.app_version};
%%          %%Name == "app_versionCode" ->
%%          %%  tools:format(InputR#input.state#state.config,"新版本Code号: ~ts ~n",[integer_to_list(list_to_integer(Value)+1)]),
%%          %%  {Name,integer_to_list(list_to_integer(Value)+1)};
%%          Name == "app_name" -> {Name,xmerl_ucs:to_utf8(Value)}
%%        end
%%                          end,Items),
%%      ItemList;

%%    {error,_}->
%%      []
%%  end.


%%写入xml方法二=================================================================
%%write_string(ItemList,SavePath)->
%%  Items = lists:foldl(fun(Item,Sum)->
%%    {Name,Value} = Item,
%%    Sum++[{string, [{name, Name}], [Value]}]
%%                      end,[],ItemList),
%%  XmlString = xmerl:export_simple([{resources, [], Items}], xmerl_xml,[{prolog, ?xml_prolog}]),
%%  unicode:characters_to_binary(XmlString),
%%  file:write_file(SavePath, list_to_binary(XmlString)),
%%  ok.
%%============================================================================

%% 写入xml方法一======================================================
%%string_to_xml_simple(ItemList) ->
%%  [ {string, [{name, K}], [V]} || {K, V} <- ItemList ].
%%resources_xml_simple(ItemList) ->
%%  {resources, string_to_xml_simple(ItemList)}.
%%make_xml(ItemList,SavePath) ->
%%  XmlString = xmerl:export_simple([resources_xml_simple(ItemList)], xmerl_xml,
%%    [{prolog, ?xml_prolog}]),

%%  unicode:characters_to_binary(XmlString),
%%  file:write_file(SavePath, list_to_binary(XmlString)),
%%ok.
%%===================================================================

%%开始打差异资源包
start_diff_cmd(InputR)->
  tools:format(InputR#input.state#state.config,"开始打差异包~n",[]),
  tools:format(InputR#input.state#state.config,"正在打包中，不要关闭软件，请稍等…… ~n",[]),

  wxPanel:disable(InputR#input.state#state.parent),
  c:cd(InputR#input.game_root),
  os:cmd("start 1_build_asset_and_code.bat"),
  start_zip_pack(InputR),
  wxPanel:enable(InputR#input.state#state.parent),
  ok.

%%开始打代码
start_code_cmd(InputR)->
  tools:format(InputR#input.state#state.config,"开始打代码~n",[]),
  tools:format(InputR#input.state#state.config,"正在打包中，不要关闭软件，请稍等…… ~n",[]),

  wxPanel:disable(InputR#input.state#state.parent),
  c:cd(InputR#input.game_root),
  os:cmd("start 1_build_code.bat"),
  tools:messageDialog(InputR#input.state#state.config,"恭喜！！！！代码打包完成"),
  tools:format(InputR#input.state#state.config,"========================= \~ts\ =========================~n",["打包结束"]),
  wxPanel:enable(InputR#input.state#state.parent),
  ok.

%%开始手动打zip文件
start_zip_cmd(InputR)->
  tools:format(InputR#input.state#state.config,"开始手动打zip包~n",[]),
  tools:format(InputR#input.state#state.config,"正在打包中，不要关闭软件，请稍等…… ~n",[]),

  wxPanel:disable(InputR#input.state#state.parent),
  c:cd(InputR#input.game_root),
  start_zip_pack(InputR),
  wxPanel:enable(InputR#input.state#state.parent),
  ok.

%%%%%%%%%%%%%%% 判断界面输入是否正确%%%%%%%%%%%%%%%%%%%%%
ui_input({Input,Doc})->
  L = length(Input),
  if
    L > 0 -> {pass,Input};
    true ->{fail,Doc}
  end.

input_f([{Input,Doc}])->
  ui_input({Input,Doc});
input_f([{Input,Doc}|T])->
  case ui_input({Input,Doc}) of
    {fail,Reason}->
      {fail,Reason};
    {pass,_}->
      input_f(T)
  end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%生成差异的zip——pack
start_zip_pack(InputR)->
  Game_Packs_Path = format_path(InputR#input.game_root++"/game_packs"),
  Versions_Xml_Path = format_path(Game_Packs_Path++"/versions.xml"),
  Versions_List = read_versions_xml(Versions_Xml_Path),
  case zip_pack_P(Versions_List) of
    {pass,PackList}->
      diff_start(PackList,InputR);
    {error,Doc} ->
      write_null_Patches(InputR),
      tools:messageDialog(InputR#input.state#state.config,Doc),
      tools:format(InputR#input.state#state.config,"========================= \~ts\ =========================~n",["打包结束"])
  end.


zip_pack_P(Versions_List) ->
  Versions_length = length(Versions_List),
  if
    Versions_length > 0 ->
      {Last_Id,Last_MaxPack} = lists:last(Versions_List),
      zip_pack_f(Versions_length,{Last_Id,list_to_integer(Last_MaxPack)},Versions_List);
    true ->
      {error,"文件夹中没有versions.xml文件或文件内容为空"}
  end.
zip_pack_f(_,{Last_Id,Last_MaxPack},_) when Last_MaxPack > 0 ->
  {Pre_Id,Pre_Pack} = {Last_Id,Last_MaxPack-1},
  {pass,[{Pre_Id,Pre_Pack},{Last_Id,Last_MaxPack}]};
zip_pack_f(_,{Last_Id,Last_MaxPack},_) when Last_MaxPack == 0 ->
  {error,"当前不存在旧资源文件."}.

%%%==========================================================================
%%%zip_pack_f(L,{Last_Id,Last_MaxPack},_) when L > 1,Last_MaxPack > 0 ->
%%%  {Pre_Id,Pre_Pack} = {Last_Id,Last_MaxPack-1},
%%%  {pass,[{Pre_Id,Pre_Pack},{Last_Id,Last_MaxPack}]};
%%%zip_pack_f(L,{Last_Id,Last_MaxPack},Versions_List) when L > 1,Last_MaxPack == 0 ->
%%%  {Pre_Id,Pre_Pack} = lists:nth(L-1,Versions_List),
%%%  {pass,[{Pre_Id,list_to_integer(Pre_Pack)},{Last_Id,Last_MaxPack}]};
%%%zip_pack_f(L,{Last_Id,Last_MaxPack},_) when L == 1,Last_MaxPack > 0 ->
%%%  {Pre_Id,Pre_Pack} = {Last_Id,Last_MaxPack-1},
%%%  {pass,[{Pre_Id,Pre_Pack},{Last_Id,Last_MaxPack}]};
%%%zip_pack_f(L,{_,Last_MaxPack},_) when L == 1,Last_MaxPack == 0 ->
%%%  {error,"当前不存在旧资源文件."}.
%%%==========================================================================

write_null_Patches(InputR)->
  Game_Packs_Path = format_path(InputR#input.game_root++"/game_packs"),
  Pack_Zip_Path = format_path(Game_Packs_Path++"/version_"++InputR#input.app_version++"/pack_zip"),
  file:make_dir(Pack_Zip_Path),
  Patches_Path = Pack_Zip_Path++"/Patches.xml",
  XmlString = xmerl:export_simple([{patches, [{appVersion,InputR#input.app_version},{maxVersion,0}], []}], xmerl_xml),
  file:write_file(Patches_Path, list_to_binary(XmlString)),
  ok.

read_versions_xml(Path)->
  case file:read_file_info(Path) of
    {ok,_}->
      {XmlElt, _} = xmerl_scan:file(Path),
      Items = xmerl_xpath:string("/versions/version", XmlElt),
      ItemList = lists:map(fun(Item)->
        [#xmlAttribute{value = Id}] = xmerl_xpath:string("/version/@id", Item),
        [#xmlAttribute{value = MaxPack}] = xmerl_xpath:string("/version/@maxPack", Item),
        {Id,MaxPack}
                           end,Items),
      ItemList;
    {error,_}->
      []
  end.

%%根据包列表信息获取资源包路径
pack_zip_path(PackList,InputR)->
  [{Pre_Id,Pre_Pack},{Last_Id,Last_MaxPack}] = PackList,
  Game_Packs_Path = format_path(InputR#input.game_root++"/game_packs"),
  if
    Last_MaxPack == 0 -> {pre,format_path(Game_Packs_Path++"/version_"++Pre_Id++"/pack_zip")};
    true -> {last,format_path(Game_Packs_Path++"/version_"++Last_Id++"/pack_zip")}
  end.

diff_start(PackList,InputR)->
  [{Pre_Id,Pre_Pack},{Last_Id,Last_MaxPack}] = PackList,
  Game_Packs_Path = format_path(InputR#input.game_root++"/game_packs"),
  io:format("~w ~n",[PackList]),
  Pre_Path = format_path(Game_Packs_Path++"/version_"++Pre_Id++"/pack_"++integer_to_list(Pre_Pack)),
  Last_Path = format_path(Game_Packs_Path++"/version_"++Last_Id++"/pack_"++integer_to_list(Last_MaxPack)),

  {ID_Status,Pack_Zip_Path} = pack_zip_path(PackList,InputR),

  Patches_Path = Pack_Zip_Path++"/Patches.xml",
  Diffs_Path = Pack_Zip_Path++"/diffs.xml",
  file:make_dir(Pack_Zip_Path),

  Pre_Lj = read_xml(Pre_Path++"/LjVersion.xml"),
  Last_Lj = read_xml(Last_Path++"/LjVersion.xml"),

  State = InputR#input.state,
  %%获取差异文件列表
  ParserList = parser_xml(Pre_Lj,Last_Lj),
%%  %%读取版本对比生成的差异表
%%  Diffs_List = read_diffXml(Diffs_Path),
  %%对比2个列表是否有差异，有差异说明需要打，没差异不需要
%%  Bool = parser_list(ParserList,Diffs_List),
  if
    length(ParserList) > 0 ->

      tools:format(State#state.config,"========================= \~ts\ =========================~n",["开始生成zip差异资源包"]),
      tools:format(State#state.config,"=============app_version : \~ts\~n",[InputR#input.app_version]),

      {PatchList,PatchVersion,AppVersion} = read_patch(Patches_Path),
      PatchVersionInt = list_to_integer(PatchVersion),
      if
        PatchVersionInt > 0 -> un_zip(PatchVersion,State,Pack_Zip_Path);
        true -> ok
      end,

      MaxVersion = list_to_integer(PatchVersion)+1,
      tools:format(State#state.config,"=========max_Version : ~ts ~n",[integer_to_list(MaxVersion)]),
      ZipDir = "Release",
      TotalZipName = "0-"++integer_to_list(MaxVersion)++".zip",
      ZipName = integer_to_list(MaxVersion)++".zip",

      %%将差异文件copy到解压的总文件夹等待压缩
      copy_file(ParserList,State,Pack_Zip_Path,ZipDir,true,Last_Path),

      %%压缩整的包0-X.zip并删除zip文件夹
      zip(Pack_Zip_Path,ZipDir,TotalZipName,State),

      %%再次copy差异文件到zip文件夹等待压缩
      copy_file(ParserList,State,Pack_Zip_Path,ZipDir,false,Last_Path),

      %%压缩差异包X.zip并删除zip文件夹
      zip(Pack_Zip_Path,ZipDir,ZipName,State),

      if
        length(AppVersion) == 0 ->
          case ID_Status of
              pre -> write_xml(Patches_Path,Pack_Zip_Path,Pre_Id,MaxVersion);
              last-> write_xml(Patches_Path,Pack_Zip_Path,InputR#input.app_version,MaxVersion)
          end;

        true -> write_xml(Patches_Path,Pack_Zip_Path,AppVersion,MaxVersion)
      end,
      write_diffXml(Diffs_Path,ParserList),

      tools:messageDialog(State#state.config,"恭喜！！！！打包完成"),
      tools:format(State#state.config,"========================= \~ts\ =========================~n",["打包结束"]);
    true ->
      tools:messageDialog(State#state.config,"该版本没有差异资源不需要打zip资源包"),
      tools:format(State#state.config,"========================= \~ts\ =========================~n",["打包结束"])
  end,
  ok.

%%读取差异版本配置Patches.xml
read_patch(PatchesPath)->
  case file:read_file_info(PatchesPath) of
    {ok,_}->
      {XmlElt, _} = xmerl_scan:file(PatchesPath),
      [#xmlAttribute{value = AppVersion}] = xmerl_xpath:string("/patches/@appVersion", XmlElt),
      [#xmlAttribute{value = MaxVersion}] = xmerl_xpath:string("/patches/@maxVersion", XmlElt),
      Items = xmerl_xpath:string("/patches/patch", XmlElt),
      ItemList = lists:map(fun(Item)->
        [#xmlAttribute{value = NameString}] = xmerl_xpath:string("/patch/@name", Item),
        [#xmlAttribute{value = Md5String}] = xmerl_xpath:string("/patch/@md5", Item),
        [#xmlAttribute{value = SizeString}] = xmerl_xpath:string("/patch/@size", Item),
        {NameString,Md5String,SizeString}
                           end,Items),
      {ItemList,MaxVersion,AppVersion};
    {error,_}->
      {[],"0",[]}
  end.

%%读取版本xml文件
read_xml(File) ->
  case file:read_file_info(File) of
    {ok,_}->
      {XmlElt, _} = xmerl_scan:file(File),
      Items = xmerl_xpath:string("/VersionAssets/VersionAsset", XmlElt),
      ItemList = lists:map(fun(Item)->
        [#xmlAttribute{value = IDString}] = xmerl_xpath:string("/VersionAsset/@ID", Item),
        [#xmlAttribute{value = Md5String}] = xmerl_xpath:string("/VersionAsset/@Md5", Item),
        [#xmlAttribute{value = SizeString}] = xmerl_xpath:string("/VersionAsset/@Size", Item),
        [#xmlAttribute{value = TypeString}] = xmerl_xpath:string("/VersionAsset/@Type", Item),
        {IDString,Md5String,SizeString,TypeString,IDString++TypeString}
                          end,Items),
      ItemList;
    {error,_} ->
      []
  end.

%%读取diff xml
read_diffXml(Diff)->
  case file:read_file_info(Diff) of
    {ok,_}  ->
      read_xml(Diff);
    {error,_} ->
      []
end.

%%创建diff xml
write_diffXml(FilePath,ParserList)->

  Items = lists:foldl(fun(Item,Sum)->
    {IDString,Md5String,SizeString,TypeString,_} = Item,
    Sum++[{'VersionAsset', [{'ID', IDString}, {'Md5', Md5String}, {'Size', SizeString},{'Type',TypeString}], []}]
                      end,[],ParserList),
  XmlString = xmerl:export_simple([{'VersionAssets', [], Items}], xmerl_xml),
  file:write_file(FilePath, list_to_binary(XmlString)),

  ok.

%%写入xml文件
write_xml(FilePath,Package_zip,App_Version,MaxVersion)->

  case file:list_dir(Package_zip) of
    {ok,FileNames}->

      La = lists:delete(".DS_Store",FileNames),
      io:format("FileNames >>>>>>>>>> = ~ts ~n",[FileNames]),
      L0 = lists:delete("Patches.xml",La),
      io:format("L0 >>>>>>>>>> = ~ts ~n",[L0]),
      L1 = lists:delete("diffs.xml",L0),
      io:format("L1 >>>>>>>>>> = ~ts ~n",[L1]),

      L2=lists:map(fun(FileName)->
        io:format("FileName >>>>>>>>>> = ~ts ~n",[FileName]),
        {Int1,TailStr}=string:to_integer(FileName),
        io:format("TailStr >>>>>>>>>> = ~ts ~n",[TailStr]),
        io:format("TailStr <<<<<<<<<< = ~ts ~n",[tl(TailStr)]),
        case string:to_integer(tl(TailStr)) of
          {error,_}-> Int2=-1;
          {Int2,_}-> ok
        end, {Int1,Int2} end,L1),

      L3=lists:sort(L2),

      L4=lists:map(fun({Int1,Int2})->
        case Int2 >0 of
          true->integer_to_list(Int1) ++ "-" ++ integer_to_list(Int2) ++ ".zip";
          _->integer_to_list(Int1) ++ ".zip"
        end
                   end,L3),

      Items = lists:foldl(fun(Item,Sum)->
        Zip_file_path = format_path(Package_zip++"/"++Item),
        %%io:format("zip file path = ~ts ~n",[Zip_file_path]),
        {FileMd5String,FileSize,FileType} = get_zip_fileInfo(Zip_file_path),
        if
          FileType == ".zip" -> Sum++[{patch, [{name, Item}, {size, FileSize}, {md5, FileMd5String}], []}];
          FileType /= ".zip" -> Sum++[]
        end

      end,[],L4),
      XmlString = xmerl:export_simple([{patches, [{appVersion,App_Version},{maxVersion,MaxVersion}], Items}], xmerl_xml),

      file:write_file(FilePath, list_to_binary(XmlString))
    ;
    {error,_}->
      ok
  end,
  ok.

%%获取zip文件信息
get_zip_fileInfo(FilePath)->

  {ok,FileBinary} = file:read_file(FilePath),
  FileString = binary_to_list(FileBinary),
  FileMd5String = lists:flatten([io_lib:format("~2.16.0b", [D]) || D <- binary_to_list(erlang:md5(FileString))]),
  {ok,FileInfo} = file:read_file_info(FilePath),
  FileSize = FileInfo#file_info.size,
  FileType = filename:extension(FilePath),
  {FileMd5String,FileSize,FileType}.

%%解析旧版和新版资源 列表 对比出差异资源 列表
parser_xml(OldList,NewList)->

  ParserList = lists:foldl(fun(Item,Sum)->
    {_,_,_,_,Key} = Item,
    OldItem = lists:keyfind(Key,5,OldList),
    if
      Item /= OldItem -> Sum++[Item];
      true -> Sum++[]
    end

                         end,[],NewList),

  ParserList.

%%判断2个列表的元素是否相等
parser_list(List1,List2)->
  if
    length(List1) /= length(List2) ->
      false;
    true ->
      ParserList = lists:foldl(fun(Item,Sum)->
        {_,_,_,_,Key} = Item,
        OldItem = lists:keyfind(Key,5,List1),
        if
          Item /= OldItem -> Sum++[Item];
          true -> Sum
        end
       end,[],List2),
      if
        length(ParserList) /= 0 -> false;
        length(ParserList) == 0 -> true
      end
  end.


%%复制差异资源到zip临时文件夹并生成zip包
copy_file(ParserList,State,Package_zip,ZipDir,Log,NewPackageUrl)->
  lists:foreach(fun(Item)->
    if
      Item /= ok ->
        {ID,_,_,Type,_} = Item,
        ItemUrl = NewPackageUrl++"/Release/"++ID++Type,
        TargetUrl = Package_zip++"/"++ZipDir++"/"++ID++Type,
        LastIndex = string:rchr(ID,$/),
        TargetDir = Package_zip++"/"++ZipDir++"/"++string:sub_string(ID,1,LastIndex),
        filelib:ensure_dir(TargetDir),
        if
          Log==true -> tools:format(State#state.config,"差异文件: ~ts ~n",[ID++Type]);
          Log==false-> no
        end,

        file:copy(ItemUrl,TargetUrl);
      true -> ok
    end
                end,ParserList),
  ok.

%%压缩文件夹
zip(Package_zip,ZipDir,ZipFile,State)->
  %%根据操作系统匹配压缩方式 osx 用 zip ，win 用 7z
  case erlang:system_info(os_type) of
    {unix,_}->
      ZipCmd = "zip -q -r -m "++ZipFile++" "++ZipDir,
      Cmd = "cd "++Package_zip++" && "++ZipCmd,
      os:cmd(Cmd);
    {win32,_}->
      Zip7zCmd = "7z a "++ZipFile++" "++ZipDir,
      WinZipDir = format_path(Package_zip++"/"++ZipDir),
      Cmd7z = "cd "++Package_zip++" && "++Zip7zCmd++" && rd/s/q "++WinZipDir,
%%      io:format("~ts ~n",[Cmd7z]),
      tools:format(State#state.config,"压缩生成补丁包: ~ts ~n",[ZipFile]),
      os:cmd(Cmd7z)
  end,
  ok.

%%解压zip
un_zip(PatchVersion,State,Package_zip)->
  ResRootUrl = Package_zip++"/",
%%  tools:format(State#state.config,"log: ~ts ~n",[PatchVersion]),
  Name = "0-"++PatchVersion++".zip",
  ZipPath = ResRootUrl++Name,
  %%根据操作系统匹配压缩方式 osx 用 zip ，win 用 7z
  case erlang:system_info(os_type) of
    {unix,_}->
      ZipCmd = "unzip -o "++ZipPath,
      Cmd = "cd "++ResRootUrl++" && "++ZipCmd,
      os:cmd(Cmd);
    {win32,_}->
      Zip7zCmd = "7z x "++ZipPath++" -aoa",
      WinZipDir = format_path(ResRootUrl),
      Cmd7z = "cd "++WinZipDir++" && "++Zip7zCmd,
      tools:format(State#state.config,"解压: ~ts ~n",[Name]),
      os:cmd(Cmd7z)
  end,

  ok.

format_path(Path)->
  case erlang:system_info(os_type) of
    {unix,_}->
      Path;
    {win32,_}->
      re:replace(Path,"\/+","\\",[global,{return, list}])
  end.



